/*
 *                    COPYRIGHT NOTICE
 *
 *           This code is copyright protected by Freedom Inc.
 *
 *              2001-2012 All Rights Are Reserved
 */
package com.freedom.oldsong.system.service.impl;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.ListIterator;
import java.util.Map;

import org.apache.commons.lang.ObjectUtils;
import org.apache.commons.lang.StringUtils;

import com.freedom.oldsong.common.AppConstants;
import com.freedom.oldsong.system.dao.MenuDao;
import com.freedom.oldsong.system.dto.MenuDto;
import com.freedom.oldsong.system.model.MenuItem;
import com.freedom.oldsong.system.service.MenuHolder;

/**
 * @author steven.wang
 *
 */
public class MenuHolderImpl implements MenuHolder {

	private MenuDao menuDao;
	
	@Override
	public List<MenuDto> getMenus() {
			List<MenuDto> holder = new ArrayList<MenuDto>();
			reorder(menuDao.getMenus(), holder, null);
			return holder;
	}
	
	@Override
	public Map<String, MenuDto> getMenusMap() {
			HashMap<String, MenuDto> menuMap = new HashMap<String, MenuDto>();
			List<MenuDto> holder = new ArrayList<MenuDto>();
			reorder(menuDao.getMenus(), holder, null);
			for (MenuDto menu : holder) {
				menuMap.put(menu.getMe().getName(), menu);
			}
			return menuMap;
	}
	
	private static void reorder(List<MenuItem> items, List<MenuDto> holder,
			MenuDto parent) {

		List<MenuDto> children = new ArrayList<MenuDto>();

		// pickup all the children belongs to the parent
		for (MenuItem item : items) {
			if(item.getSrc()!=null && item.getSrc().startsWith("/")){
				item.setSrc(AppConstants.getConfigValue(AppConstants.SERVER_ADRESS)+item.getSrc());
			}
			if (parent == null) {
				if (item.getParent() == null) {
					children.add(new MenuDto(null, item)); // top menu
				}
			} else if (ObjectUtils.equals(parent.getMe().getName(), item
					.getParent())) {
				children.add(new MenuDto(parent, item));
			}
		}

		// if there's no children belong to this parent, process end
		if (children.isEmpty()) {
			return;
		}

		// sort by after.
		children = sortByAfter(children);

		recursion(items, holder, parent, children);

	}

	/**
	 * @param items
	 * @param holder
	 * @param parent
	 * @param children
	 */
	private static void recursion(List<MenuItem> items, List<MenuDto> holder,
			MenuDto parent, List<MenuDto> children) {
		// insert the menuitems just after their parent.
		if (parent == null) { // top menu
			holder.addAll(children);
		} else {
			parent.setSubMenus(children);
		}

		// remove all processed menuitem
		for (MenuDto menu : children) {
			items.remove(menu.getMe().getName());
		}

		// do it again or all children.
		// this time, they will be parent.
		for (MenuDto menu : children) {
			reorder(items, holder, menu);
		}
	}
	
	private static List<MenuDto> sortByAfter(List<MenuDto> menus) {

		List<MenuDto> result = new ArrayList<MenuDto>();
		MenuDto after = null;
		String current = null;
		String menuName = null;
		while (menus.size() != 0) {
			boolean found = false;
			// find the menuitem after current
			ListIterator<MenuDto> it = menus.listIterator();
			while (it.hasNext()) {
				MenuDto menu = it.next();
				menuName= menu.getMe().getName();
				if (StringUtils.equals(current, menu.getMe().getAfter())) {
					result.add(menu);
					menu.setAfter(after);
					current = menuName;
					after = menu;
					it.remove();
					found = true;
					break;
				}
			}

			if (!found) {
				throw new IllegalStateException(
						"There's one broken menu chain!");
			}

		}

		return result;

	}
	
	public void setMenuDao(MenuDao menuDao) {
		this.menuDao = menuDao;
	}

}
